#include "Serveur.h"
#include "TemperatureSensor.h"
#include "ServoMotor.h"
#include "I2CManager.h"
#include "GPIOManager.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>

/* 1001 (A2=0)(A1=0)(A0=0) */
#define TEMPEATURE_SENSOR_1 0x48
/* 1001 (A2=1)(A1=1)(A0=1) */
#define TEMPEATURE_SENSOR_2 0x4F

int splitRequest(char* data, char* result)
{
	char commande[20];
	sscanf(data, "%s %s", commande, result);
	
	if( strcmp(commande, "cmd:") == 0 )
	{
		return 1;
	}
	else if( strcmp(commande, "msg:") == 0 )
	{
		return 2;
	}
	
	return -1;
}

FILE* initGPIO(int pin)
{
	FILE* modeFile = openGpioModeFile(pin);
	
	if( modeFile == NULL )
	{
		printf("Erreur ouverture du fichier GPIOMode %d", pin);
		return NULL;
	}
	
	pinMode(modeFile, OUTPUT);
	fclose(modeFile);
	
	return openGpioPinFile(pin, "w");
}

void initTemperatureSensor(int i2CFile)
{
	if( setTemperatureSensor(i2CFile, TEMPEATURE_SENSOR_1, RESOLUTION_12 | SHUTDOWN | ONE_SHOT) < 0 )
	{
		perror("setTemperatureSensor 1");
		exit(1);
	}
	if( setTemperatureSensor(i2CFile, TEMPEATURE_SENSOR_2, RESOLUTION_12 | SHUTDOWN | ONE_SHOT) < 0 )
	{
		perror("setTemperatureSensor 2");
		exit(1);
	}
}

void getTemperatures(int i2CFile, float* temp1, float* temp2)
{
	initTemperatureSensor(i2CFile);
	
	if( getAmbientTemperature(i2CFile, TEMPEATURE_SENSOR_1, temp1) < 0 )
	{
		printf("Erreur lors de la recuperation de la temperature\n");
		exit(1);
	}
	
	if( getAmbientTemperature(i2CFile, TEMPEATURE_SENSOR_2, temp2) < 0 )
	{
		printf("Erreur lors de la recuperation de la temperature\n");
		exit(1);
	}
}

void callback(int socket)
{
	char buffer[4096];
	int nbBytesReceived;
	int ret = 0;
	fd_set read_fd_set;
	float temperature1 = 0.0f;
	float temperature2 = 0.0f;
	int i2CFile = 0;
	FILE* pinFile2 = NULL;
	FILE* pinFile5 = NULL;
	
	/* timeout pour le select */
	struct timeval timeout;
	
	/* le select attend 2 secondes */
	timeout.tv_sec = 2;
	timeout.tv_usec = 0;
	
	printf("Nouvelle connexion sur le serveur !!\n");
	
	/* Initialisation des broches 2 et 5 */
	pinFile2 = initGPIO(2);
	pinFile5 = initGPIO(5);
	
	if( pinFile2 == NULL )
	{
		printf("Erreur ouverture du fichier pinFiles2");
		return;
	}
	if( pinFile5 == NULL )
	{
		printf("Erreur ouverture du fichier pinFiles5");
		return;
	}
	
	pinWrite(pinFile2, OFF);
	spin(pinFile5, 0);
	
	/* I2C Initialisation */
	i2CFile = getI2CFile();
	if( i2CFile < 0 )
	{
		printf("Erreur lors de l'ouverture du fichier\n");
		exit(1);
	}
	
	/* Configuration des capteurs de temperature*/
	initTemperatureSensor(i2CFile);
	
	while(1)
	{
		FD_ZERO(&read_fd_set);
		FD_SET(socket, &read_fd_set);
		
		ret = select(socket + 1, &read_fd_set, NULL, NULL, &timeout);
		
		if( ret < 0 )
		{
			perror("select");
			break;
		}
		/* Tous les 5 secondes on interroge les capteurs de temperature */
		else if( ret == 0 )
		{	
			/* recuperation des valeurs des capteurs de temperature */
			getTemperatures(i2CFile, &temperature1, &temperature2);
			
			timeout.tv_sec = 2;
			timeout.tv_usec = 0;
		}
		else if( FD_ISSET(socket, &read_fd_set) )
		{
			/* des données sont disponibles sur le socket */
			/* traitement des données */
			if( ( nbBytesReceived = recv(socket, buffer, sizeof(buffer) - 1, 0) ) > 0 )
			{
				buffer[nbBytesReceived] = '\0';
				
				char request[60];
				switch( splitRequest(buffer, request) )
				{
					/* Commande */
					case 1:
						if( strcmp(request, "ledOn") == 0 )
						{						
							printf("ledOn: allumer led\n");
							pinWrite(pinFile2, ON);
						}
						else if( strcmp(request, "ledOff") == 0 )
						{
							printf("ledOff: eteindre led\n");
							pinWrite(pinFile2, OFF);
						}
						else if( strcmp(request, "getTemp") == 0 )
						{
							printf("getTemp: recuperation temperature 1 %f\n", temperature1);
							printf("getTemp: recuperation temperature 2 %f\n", temperature2);
							sprintf(buffer, "temp1: %f;temp2: %f;", temperature1, temperature2);
							if( send(socket, buffer, strlen(buffer), 0) == -1 )
							{
								printf("erreur lors de l'envoie du message\n");
							}
						}
						/* Commande avec parametre*/
						else
						{
							printf("Requete %s\n", buffer);
							char cmd[20];
							char commande[20];
							char param[60];
							sscanf(buffer, "%s %s %s", cmd, commande, param);
							
							if( strcmp(commande, "spin") == 0 )
							{
								float angle = atof(param);
								spin(pinFile5, angle);
								printf("spin : %f\n", angle);
							}
							else
							{
								printf("Commande inconnue\n");
								break;
							}
						}
						break;
					/* Message */
					case 2:
						printf("%s\n", request);
						break;
					default:
						printf("Bad request\n");
						break;
				}		
			}
			else
			{
				break;
			}
		}
	 }
	 
	fclose(pinFile2);
	fclose(pinFile5);
	
	printf("Fin de la communication\n");
}

int main(int argc, char** argv)
{
	if( argc < 2 )
	{
		printf("Usage : %s [port]\n", argv[0]);
		return EXIT_FAILURE;
	}
	
	int port = 0;
	
	if( sscanf(argv[1], "%d", &port) == EOF )
	{
		printf("Port must be an integer\n");
		return EXIT_FAILURE;
	}
	
	printf("Port : %d\n", port);
	
	int socket = initServeur(port, 10);
	
	serveurLoop(socket, callback);
	
	return 0;
}
